<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
        <meta
            name="viewport"
            content="width=device-width, minimal-ui, viewport-fit=cover, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"
        />
        <link rel="icon" type="image/png" href="assets/favicon.png" />

        <title>OGL • Cube Map</title>
        <link href="assets/main.css" rel="stylesheet" />
    </head>
    <body>
        <div class="Info">
            Cube Map. Texture by <a href="http://www.humus.name" target="_blank">Humus</a>
            <div id="dropdown">
                <label for="zoom-style">Zoom Style:</label>
                <select name="zoom-style" id="zoom-style">
                    <option value="dolly">Dolly</option>
                    <option value="fov">FOV</option>
                </select>
            </div>
        </div>
        <script type="module">
            import { Renderer, Camera, Transform, Texture, Program, Geometry, Mesh, Box, Orbit } from '../src/index.mjs';

            const vertex = /* glsl */ `
                attribute vec3 position;

                uniform mat4 modelViewMatrix;
                uniform mat4 projectionMatrix;

                varying vec3 vDir;

                void main() {
                    vDir = normalize(position);
                    
                    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
                }
            `;

            const fragment = /* glsl */ `
                precision highp float;

                // uniform type is samplerCube rather than sampler2D
                uniform samplerCube tMap;

                varying vec3 vDir;

                void main() {

                    // sample function is textureCube rather than texture2D
                    vec3 tex = textureCube(tMap, vDir).rgb;
                    
                    gl_FragColor.rgb = tex;
                    gl_FragColor.a = 1.0;
                }
            `;

            {
                const renderer = new Renderer({ dpr: 2 });
                const gl = renderer.gl;
                document.body.appendChild(gl.canvas);
                gl.clearColor(1, 1, 1, 1);

                const camera = new Camera(gl, { fov: 45 });
                camera.position.set(-2, 1, -3);

                const controls = new Orbit(camera);

                document.querySelector('#dropdown').addEventListener('change', ({ target: { value } }) => {
                    controls.zoomStyle = value;
                });

                function resize() {
                    renderer.setSize(window.innerWidth, window.innerHeight);
                    camera.perspective({ aspect: gl.canvas.width / gl.canvas.height });
                }
                window.addEventListener('resize', resize, false);
                resize();

                const scene = new Transform();

                // Create an empty texture using the gl.TEXTURE_CUBE_MAP target
                const texture = new Texture(gl, {
                    target: gl.TEXTURE_CUBE_MAP,
                });

                loadImages();
                async function loadImages() {
                    function loadImage(src) {
                        return new Promise((res) => {
                            const img = new Image();
                            img.onload = () => res(img);
                            img.src = src;
                        });
                    }

                    // Must be in this order (it's a WebGL thing)
                    // gl.TEXTURE_CUBE_MAP_POSITIVE_X Right
                    // gl.TEXTURE_CUBE_MAP_NEGATIVE_X Left
                    // gl.TEXTURE_CUBE_MAP_POSITIVE_Y Top
                    // gl.TEXTURE_CUBE_MAP_NEGATIVE_Y Bottom
                    // gl.TEXTURE_CUBE_MAP_POSITIVE_Z Back
                    // gl.TEXTURE_CUBE_MAP_NEGATIVE_Z Front

                    const images = await Promise.all([
                        loadImage('assets/cube/posx.jpg'),
                        loadImage('assets/cube/negx.jpg'),
                        loadImage('assets/cube/posy.jpg'),
                        loadImage('assets/cube/negy.jpg'),
                        loadImage('assets/cube/posz.jpg'),
                        loadImage('assets/cube/negz.jpg'),
                    ]);

                    // Once all are loaded, we can update the texture image, which will upload them
                    texture.image = images;
                }

                const geometry = new Box(gl);

                const program = new Program(gl, {
                    vertex,
                    fragment,
                    uniforms: {
                        tMap: { value: texture },
                    },
                    cullFace: null,
                });

                const skybox = new Mesh(gl, { geometry, program });
                skybox.setParent(scene);
                skybox.scale.set(20);

                const mesh = new Mesh(gl, { geometry, program });
                mesh.setParent(scene);

                requestAnimationFrame(update);
                function update(t) {
                    requestAnimationFrame(update);

                    controls.update();

                    mesh.rotation.y += 0.003;
                    renderer.render({ scene, camera });
                }
            }
        </script>
    </body>
</html>
